home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 018 / browser / browser.c next >
C/C++ Source or Header  |  1995-03-17  |  11KB  |  380 lines

  1. /*
  2.  * browser - Rummage around on disks.
  3.  *
  4.  *    copyright (c) 1986, Mike Meyer
  5.  *
  6.  * Permission is hereby granted to distribute this program, so long as this
  7.  * source file is distributed with it, and this copyright notice is not
  8.  * removed from the file.
  9.  *
  10.  * Locks, general -    do I need a stack of locks, one per directory level?
  11.  *            do I have to free the lock in done?
  12.  */
  13.  
  14. #include <exec/types.h>
  15. #include <graphics/gfxbase.h>
  16. #include <libraries/dos.h>
  17. #include <libraries/dosextens.h>
  18. #include <intuition/intuition.h>
  19. #include <stdio.h>
  20.  
  21. #define INTUITION_REV        1
  22. #define GRAPHICS_REV        1
  23.  
  24. #define LONGEST_NAME        80    /* Longest file name we can deal with */
  25. #define LONGEST_LINE        256    /* Longest line we will deal with */
  26. #define AVG_LINE_LENGTH        66    /* A guess, tune it if you need to */
  27.  
  28. #define UP_GADGET        ((unsigned short) 0)
  29. #define DOWN_GADGET        ((unsigned short) 1)
  30. #define GWIDTH            16    /* Width of my two gadgets */
  31. #define GHEIGHT            9    /* and their heights */
  32.  
  33. /*
  34.  * Pictures for the up and down arrows
  35.  */
  36. static USHORT arrows[2][GHEIGHT] = {
  37.     {0xFE7F, 0xFC3F, 0xFA5F, 0xF66F,    /* Up */
  38.      0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F},
  39.     {0xFE7F, 0xFE7F, 0xFE7F, 0xFE7F,    /* Down */
  40.      0xFE7F, 0xF66F, 0xFA5F, 0xFC3F, 0xFE7F}
  41.     } ;
  42. /*
  43.  * Now, the Image structures that use the arrows
  44.  */
  45. static struct Image Arrow_Image[2] = {
  46.     {0, 0, GWIDTH, GHEIGHT, 1, arrows[UP_GADGET], 1, 0,  /* Up */
  47.         (struct Image *) NULL},
  48.     {0, 0, GWIDTH, GHEIGHT, 1, arrows[DOWN_GADGET], 1, 0,  /* Down */
  49.         (struct Image *) NULL}
  50.     } ;
  51. /*
  52.  * Now, my two Gadget structures
  53.  */
  54. static struct Gadget Up_Gadget = {
  55.     (struct Gadget *) NULL,
  56.     0, 1 - GHEIGHT,            /* Left, Top */
  57.     GWIDTH, GHEIGHT,
  58.     GRELBOTTOM | GADGIMAGE        /* Standard bottom border gadget */
  59.     | GADGHCOMP,
  60.     RELVERIFY | BOTTOMBORDER,    /* Messages when released */
  61.     BOOLGADGET,            /* These be boolean gadgets */
  62.     (APTR) &(Arrow_Image[UP_GADGET]),
  63.     (APTR) NULL,            /* No rendering image, using HCOMP */
  64.     (struct IntuiText *) NULL,
  65.     0,                /* No mutex */
  66.     (APTR) NULL,            /* Nothing special */
  67.     UP_GADGET,            /* Yes, this is the up gadget */
  68.     (APTR) NULL            /* And nothing of mine */
  69.     } ;
  70.  
  71. static struct Gadget Down_Gadget = {
  72.     &Up_Gadget,            /* Next gadget is Up_Gadget */
  73.     GWIDTH + 2, 1 - GHEIGHT,    /* Left, Top */
  74.     GWIDTH, GHEIGHT,
  75.     GRELBOTTOM | GADGIMAGE        /* Standard bottom border gadget */
  76.     | GADGHCOMP,
  77.     RELVERIFY | BOTTOMBORDER,    /* Messages when released */
  78.     BOOLGADGET,            /* These be boolean gadgets */
  79.     (APTR) &(Arrow_Image[DOWN_GADGET]),
  80.     (APTR) NULL,            /* No rendering image, using HCOMP */
  81.     (struct IntuiText *) NULL,
  82.     0,                /* No mutex */
  83.     (APTR) NULL,            /* Nothing special */
  84.     DOWN_GADGET,            /* Yes, this is the up gadget */
  85.     (APTR) NULL            /* And nothing of mine */
  86.     } ;
  87. /*
  88.  * Now, the window for it all
  89.  */
  90. static struct NewWindow New_Window = {
  91.     0, 0, 640, 200,            /* Full screen */
  92.     -1, -1,                /* Default pens */
  93.     MENUPICK | CLOSEWINDOW        /* I want to know about menupicks */
  94.     | GADGETUP,            /* Window closes and gadgets */
  95.     ACTIVATE            /* Standard window */
  96.     | SMART_REFRESH | NOCAREREFRESH | SIZEBBOTTOM
  97.     | WINDOWSIZING | WINDOWDEPTH | WINDOWCLOSE | WINDOWDRAG,
  98.     &Down_Gadget,            /* Add my gadgets */
  99.     (struct Image *) NULL,
  100.     "Browser 0.0",            /* Title */
  101.     (struct Screen *) NULL,
  102.     (struct BitMap *) NULL,
  103.     100, 40,            /* Minimum sizes */
  104.     640, 200,            /* Maximum sizes */
  105.     WBENCHSCREEN            /* and put it on the workbench */
  106.     } ;
  107. /*
  108.  * My very own variables (mostly for done)
  109.  */
  110. static struct Window    *My_Window = NULL ;
  111. static FILE        *infile = NULL ;    /* Current input file */
  112. static void        Page_File(unsigned short) ;
  113.  
  114. /*
  115.  * And someone else's variables
  116.  */
  117. struct IntuitionBase    *IntuitionBase ;
  118. struct GfxBase        *GfxBase ;
  119. extern struct Menu    *AutoMenu ;
  120.  
  121. /*
  122.  * Finally, declare the string twiddling functions as voids
  123.  */
  124. void    strcat(char *, char *), strcpy(char *, char *) ,
  125.     strncat(char *, char *, int) ;
  126.  
  127. #ifdef    DEBUG
  128. main() {
  129. #else
  130. _main() {
  131. #endif
  132.     register struct IntuiMessage    *message, *GetMsg(struct MsgPort *) ;
  133.     register unsigned short        class, code ;
  134.  
  135.     /* Set up the world this lives in */
  136.  
  137.     if ((IntuitionBase = (struct IntuitionBase *)
  138.         OpenLibrary("intuition.library", INTUITION_REV)) == NULL)
  139.         done(20, "can't open intuition library") ;
  140.  
  141.     if ((GfxBase = (struct GfxBase *)
  142.         OpenLibrary("graphics.library", GRAPHICS_REV)) == NULL)
  143.         done(20, "can't open graphics library") ;
  144.  
  145.     if ((My_Window = (struct Window *) OpenWindow(&New_Window)) == NULL)
  146.         done(20, "can't open the window") ;
  147.  
  148.     SetAPen(My_Window -> RPort, 1) ;    /* Should be default! */
  149.  
  150.     /* Set up the first menu level */
  151.     Menu_Init() ;
  152.     Menu_Add("disks ", TRUE) ;
  153.     Menu_Item_Add("df0:", ITEMENABLED, 0, 0) ;
  154.     Menu_Item_Add("df1:", ITEMENABLED, 0, 0) ;
  155.     Menu_Item_Add("ram:", ITEMENABLED, 0, 0) ;
  156.     SetMenuStrip(My_Window, AutoMenu) ;
  157.  
  158.     /* Now spin on messages, handling them as they arrive */
  159.     for (;;) {
  160.         Wait(1 << My_Window -> UserPort -> mp_SigBit) ;
  161.         while (message = GetMsg(My_Window -> UserPort)) {
  162.             class = message -> Class ;
  163.             code = message -> Code ;
  164.             ReplyMsg(message) ;
  165.  
  166.             switch (class) {
  167.                 case CLOSEWINDOW:
  168.                     done(0, "exit") ;
  169.  
  170.                 case MENUPICK:
  171.                     if (code != MENUNULL)
  172.                         Examine_Menu_Pick(code) ;
  173.                     break ;
  174.  
  175.                 case GADGETUP:
  176.                     Page_File(((struct Gadget *) (message -> IAddress)) -> GadgetID) ;
  177.                     break ;
  178.  
  179.                 default:
  180. #ifdef    DEBUG
  181.                     printf("browser: intuition event 0x%x\n", class) ;
  182. #endif
  183.                     done(20, "unexpected intution event") ;
  184.                     break ;
  185.                 }
  186.             }
  187.         }
  188.     done(20, "broke out of never-breaking loop!") ;
  189.     }
  190. /*
  191.  * Examine_Menu_Pick - takes a menu pick, and twiddles the state variables
  192.  *    to match that pick.
  193.  */
  194. static
  195. Examine_Menu_Pick(Menu_Number) unsigned short Menu_Number; {
  196.     register unsigned short    level, i, dirp ;
  197.     register char        *cp ;
  198.     char            *name, *strchr(char *, int) ;
  199.     struct MenuItem        *ItemAddress(struct Menu *, unsigned short) ;
  200.     /* State variables that describe the current directory */
  201.     static char        Dir_Name[LONGEST_NAME] ;
  202.     static unsigned short    Menu_Level = 0 ;
  203.  
  204.     name = ((struct IntuiText *)
  205.         (ItemAddress(AutoMenu, Menu_Number) -> ItemFill)) -> IText ;
  206.     level = MENUNUM(Menu_Number) ;
  207.  
  208.     /* Got what we want, so clear the menu to avoid confusing the user */
  209.     ClearMenuStrip(My_Window) ;
  210.  
  211.     /* set dirp to FALSE if the name is not a directory or disk */
  212.     dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;
  213.  
  214.     /* First, set the directory name right */
  215.     if (level > Menu_Level)            /* Not possible, die */
  216.         done(20, "impossible menu value returned") ;
  217.     else if (level == 0)            /* picked a new disk */
  218.         Dir_Name[0] = '\0' ;
  219.     else if (level < Menu_Level) {        /* Throw away some levels */
  220.         for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
  221.             if (cp == NULL) done(20, "broken file name") ;
  222.             cp = strchr(cp, '/') ;
  223.             }
  224.         if (cp == NULL) done(20, "broken file name") ;
  225.         *++cp = '\0' ;
  226.         }
  227.     /* else Menu_Level == level, chose a file at current level */
  228.  
  229.     /* Now, fix up the menu and it's state variable */
  230.     while (Menu_Level > level) {
  231.         Menu_Level-- ;
  232.         Menu_Pop() ;
  233.         }
  234.  
  235.     /* If we added a directory, tack it onto the name */
  236.     if (dirp) {
  237.         Menu_Level++ ;
  238.         strncat(Dir_Name, name,    LONGEST_NAME - strlen(Dir_Name) - 1) ;
  239.         }
  240.  
  241.     /* Now, tell the user all about it */
  242.     if (dirp) Add_Dir(Dir_Name, name) ;
  243.     else Display_File(Dir_Name, name) ;
  244.     SetMenuStrip(My_Window, AutoMenu) ;
  245.     }
  246. /*
  247.  * Add_Dir - given a dir and a name, add the menu name with the files in
  248.  *    dir as entries.
  249.  */
  250. static
  251. Add_Dir(dir, name) char *dir, *name; {
  252.     register char            *last_char ;
  253.     register struct FileLock    *my_lock, *Lock(char *, int) ;
  254.     unsigned short            count ;
  255.     struct FileInfoBlock        File_Info ;
  256.     static char            Name_Buf[LONGEST_NAME] ;
  257.  
  258.     /* Fix up the trailing / if it needs it */
  259.     last_char = &dir[strlen(dir) - 1] ;
  260.     if (*last_char == '/') *last_char = '\0' ;
  261.  
  262.     /* Now, start on the directory */
  263.     if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) {
  264. #ifdef    DEBUG
  265.         printf("browser: error trying to lock %s, IoErr says %d\n",
  266.                 dir, IoErr()) ;
  267. #endif
  268.         done(20, "can't get lock on file") ;
  269.         }
  270.  
  271.     if (!Examine(my_lock, &File_Info)) done(20, "can't examine file") ;
  272.     if (File_Info . fib_DirEntryType < 0)
  273.         done(20, "Add_Dir called with a non-directory") ;
  274.  
  275.     Menu_Add(name, TRUE) ;
  276.     for (ExNext(my_lock, &File_Info), count = 0;
  277.          IoErr() != ERROR_NO_MORE_ENTRIES;
  278.          ExNext(my_lock, &File_Info), count++)
  279.         if (File_Info . fib_DirEntryType < 0)
  280.             Menu_Item_Add(File_Info . fib_FileName, ITEMENABLED,
  281.                 0, 0) ;
  282.         else {
  283.             strcpy(Name_Buf, File_Info . fib_FileName) ;
  284.             strcat(Name_Buf, "/") ;
  285.             Menu_Item_Add(Name_Buf, ITEMENABLED, 0, 0) ;
  286.             }
  287.     if (count == 0) Menu_Item_Add("EMPTY", 0, 0, 0) ;
  288.  
  289.     /* Put everything back */
  290.     if (*last_char == '\0') *last_char = '/' ;
  291.     UnLock(my_lock) ;
  292.     }
  293. /*
  294.  * Display_File - given a directory path and file name, put the first page of
  295.  *    the file in the window.
  296.  */
  297. static
  298. Display_File(dir, name) char *dir, *name; {
  299.     static char    File_Name[LONGEST_NAME] ;
  300.     FILE        *fopen(char *, char *) ;
  301.  
  302.     /* Get the file name */
  303.     strcpy(File_Name, dir) ;
  304.     strcat(File_Name, name) ;
  305.  
  306.     if (infile != NULL) fclose(infile) ;
  307.     if ((infile = fopen(File_Name, "r")) == NULL) {
  308. #ifdef    DEBUG
  309.         printf("File: %s\n", File_Name) ;
  310. #endif
  311.         done(20, "can't open file") ;
  312.         }
  313.     Page_File(DOWN_GADGET) ;        /* Down from page 0 */
  314.     }
  315. /*
  316.  * Page_File - move the file up or down one "page"
  317.  */
  318. static void
  319. Page_File(direction) int direction; {
  320.     /* These two should be registers, but it the it breaks the compiler */
  321.     short    Page_Length, where ;
  322.     static char    buffer[LONGEST_LINE], *blanks ;
  323.  
  324.     if (infile == NULL) return ;
  325.  
  326.     blanks =
  327. "                                                                                 " ;
  328.  
  329.     Page_Length = (My_Window -> Height - 20) / 8 ;
  330.  
  331.     if (direction == UP_GADGET) {        /* Seek back one page */
  332.         if (ftell(infile) < AVG_LINE_LENGTH * (Page_Length + 2))
  333.             fseek(infile, 0L, 0) ;
  334.         else {
  335.             fseek(infile, (long) -Page_Length * AVG_LINE_LENGTH, 1) ;
  336.             fgets(buffer, LONGEST_LINE, infile) ;
  337.             }
  338.         }
  339.     else if (direction != DOWN_GADGET)
  340.         done(20, "Illegal argument to Page_File") ;
  341.  
  342.     for (where = 17; Page_Length--; where += 8) {
  343.         Move(My_Window -> RPort, 3, where) ;
  344.         Text(My_Window -> RPort, blanks, 79) ;
  345.         Move(My_Window -> RPort, 3, where) ;
  346.         if (fgets(buffer, LONGEST_LINE, infile) == NULL)
  347.             return ;
  348.         if (strlen(buffer) < LONGEST_LINE - 1)
  349.             Text(My_Window -> RPort, buffer, strlen(buffer) - 1) ;
  350.         else {
  351.             Text(My_Window -> RPort, "Long line read!", 15) ;
  352.             fclose(infile) ;
  353.             infile = NULL ;
  354.             return ;
  355.             }
  356.         }
  357.     }
  358. /*
  359.  * done - just close everything that's open, and exit.
  360.  */
  361. static
  362. done(how, why) int how; char *why; {
  363.  
  364.     if (My_Window) {
  365.         ClearMenuStrip(My_Window) ;
  366.         Menu_Clear() ;
  367.         CloseWindow(My_Window) ;
  368.         }
  369.     if (GfxBase) CloseLibrary(GfxBase) ;
  370.     if (IntuitionBase) CloseLibrary(IntuitionBase) ;
  371.     if (infile) fclose(infile) ;
  372.  
  373. #ifdef    DEBUG
  374.     printf("browser: %s\n", why) ;
  375. #endif
  376.     (void) OpenWorkBench() ;
  377.     exit(how) ;
  378.     }
  379.  
  380.